# -*- coding: utf-8 -*-
# Copyright (C) 2007 Boris Dušek
# See the file LICENCE in the top-level directory of this distribution
# for licensing information.
# vim:ts=4:sw=4:et

from army.core import memory

class PagedMemoryEngine(memory.DecoratorMemoryEngine):
    """Implements memory paging.

    This makes it possible to use memory locations spread all over virtual
    range (which can be e.g. of scale of 4GB), but to store it in a file
    whose size is the total real memory consumption (e.g. 20MB).

    Example:

    we have used 1 byte at 0x00000000 and 1 byte at 0xffffffff.
     * without paging, 4GB file would be needed
     * with paging, 2 pages are created, so with page size of e.g. 4kB,
       8kB file would be used

    Memory pages are created whenever they are accessed.

    """

    def __init__(self,engine,page_size_exp=12):
        """Initializes the paged memory model.

        engine - engine on top of which do paging
        page_size_exp - page size is 2**page_size_exp

        """
        self.engine = engine
        self.pages = {}
        self.page_size_exp = page_size_exp
        self.page_size = 2**self.page_size_exp

    def _page_addr(self,page,offset):
        if not page in self.pages:
            self.pages[page] = (len(self.pages))
        return (self.pages[page] << self.page_size_exp) + offset

    def _addr(self,address):
        page,offset = divmod(address,self.page_size)
        return self._page_addr(page,offset)

    def read(self,address):
        return self.engine.read(self._addr(address))

    def write(self,address,byte):
        return self.engine.write(self._addr(address),byte)
